import * as THREE from "three";
import { roadMaterial, lineMaterial,pointMaterial } from '../../material'
import { Line2 } from 'three/examples/jsm/lines/Line2'
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry'
export default class Calculate {
  constructor(editor) {
    this.type = 'Curve';
    this.name = '';
    this.roadMaterial = roadMaterial;
    this.lineMaterial = lineMaterial;
    this.pointMaterial = pointMaterial;
    this.lineMesh = null
    this.roadMesh = null
    this.editor = editor;
    /** 车道宽度  等间距距离 */
    this.laneWidth = 10
    this.radius = 10
  }
  /** 获取两个点的切线 */
  getTangentAt(pointsArr, i) {
    let p1 = null
    let p2 = null
    if (pointsArr[i + 1]) {
      p1 = pointsArr[i]
      p2 = pointsArr[i + 1]
    } else {
      p1 = pointsArr[i - 1]
      p2 = pointsArr[i]
    }
    let tangent = p1.clone().sub(p2).normalize();
    return tangent
  }
  /** 获取指定的点两边的点位置 */
  getSpecifiedPoint(arr, index) {
    let p1 = null
    let p2 = null
    if (arr[index + 1]) {
      p1 = arr[index]
      p2 = arr[index + 1]
    } else {
      p1 = arr[index - 1]
      p2 = arr[index]
    }
    let point = arr[index]
    let tangent = this.getTangentAt(arr, index)
    let zUnitVector = new THREE.Vector3(0, 0, 1); //沿着z轴方向单位向量
    // 切线二维向量转三维向量
    let tangentV3 = new THREE.Vector3(tangent.x, tangent.y, 0);
    // 切线绕z轴旋转90度计算垂线
    let vertical = tangentV3.clone().applyAxisAngle(zUnitVector, Math.PI / 2);

    let a0 = point.clone().add(vertical.clone().multiplyScalar(this.laneWidth / 2));
    let b0 = point.clone().add(vertical.clone().multiplyScalar(- this.laneWidth / 2));
    if (this.cross(a0, p1, p2) > 0) {
      return [a0, b0]
    } else {
      return [b0, a0]
    }
  }
  /** 根据叉乘计算一个点在向量的左边还是右边，大于0在左边 */
  cross(p0, p1, p2) {
    const [ax, ay, bx, by] = [
      p1.x - p0.x,
      p1.y - p0.y,
      p2.x - p0.x,
      p2.y - p0.y,
    ];
    return ax * by - bx * ay;
  }
  

  listen() {
    this.createLine()
    this.createPlane()
  }
  dispose() {
    this.editor.removeMesh(this.roadMesh)
    this.editor.removeMesh(this.lineMesh)
    this.lineMesh.geometry.dispose()
    this.lineMesh.material.dispose()
    this.roadMesh.geometry.dispose()
    this.roadMesh.material.dispose()
    this.lineMesh = null
    this.roadMesh = null
  }
  createLine() {
    let geometry = new LineGeometry()
    this.lineMesh = new Line2(geometry, lineMaterial)
    this.lineMesh.name = '道路中心辅助线'
    this.editor.addMesh(this.lineMesh)
  }
  createPlane() {
    let shape = new THREE.Shape();
    //填充轮廓生成一个带状平面几何体ShapeBufferGeometry
    let geometry = new THREE.ShapeBufferGeometry(shape);
    this.roadMesh = new THREE.Mesh(geometry, roadMaterial);
    this.roadMesh.name = '道路'
    this.editor.addMesh(this.roadMesh)
  }
  getOnCurvePoint(arr) {
    if (arr.length === 2) {
      return arr
    }
    arr = arr.map(p => new THREE.Vector3(p.x, p.y))
    let pointsArr = []; //圆弧顶点坐标集合
    pointsArr.push(new THREE.Vector2(arr[0].x, arr[0].y))
    for (let i = 1; i < arr.length - 1; i++) { //注意两端的点不用圆角化
      // 三个点坐标
      let p1 = arr[i - 1];
      let p2 = arr[i];
      let p3 = arr[i + 1];
      // 计算三个点构成的两条线的方向
      let dir1 = p1.clone().sub(p2).normalize();
      let dir2 = p3.clone().sub(p2).normalize();
      // 向量叉乘结果用来判断：1.直线是否重合 2.过渡圆弧旋转方向
      let crossDirection = dir1.clone().cross(dir2).z;
      if (crossDirection == 0) {
        //  两直线重合不用圆角化，直接插入交叉点p2坐标即可
        // curve.curves.push(new THREE.LineCurve(arr[i - 1], p2));
        pointsArr.push(p2)
      } else {
        // 两条直线角平分线方向
        let angleBisector = dir2.clone().add(dir1).normalize(); // 角平分线
        let angCos = dir1.clone().dot(dir2); //两条直线方向向量夹角余弦值
        let ang = Math.acos(angCos);
        // 对边 / 斜边 = sin  sideLength = 半径 / sin
        let sinLength = this.radius / Math.sin(ang / 2); //圆心与两条直接交叉点距离
        let circleCenter = p2.clone().add(angleBisector.clone().multiplyScalar(sinLength))
        // console.log('圆心', circleCenter)

        // let z = new THREE.Vector3(0, 0, 1);
        let x = new THREE.Vector3(1, 0, 0);
        // 垂足与两直线交点距离   邻边 / 斜边  = cos
        let cosLength = sinLength * Math.cos(ang / 2);
        let a1 = p2.clone().add(dir1.clone().multiplyScalar(cosLength))
        let a2 = p2.clone().add(dir2.clone().multiplyScalar(cosLength))
        let dir1Vector = a1.clone().sub(circleCenter).normalize();
        let dir2Vector = a2.clone().sub(circleCenter).normalize();
        // 通过applyAxisAngle快速计算垂线,需要根据转弯方向，考虑旋转方向
        // let dir1Vector = dir1.clone().applyAxisAngle(z, Math.PI / 2);
        // let dir2Vector = dir2.clone().applyAxisAngle(z, Math.PI / 2);
        let cosAng1 = Math.acos(dir1Vector.clone().dot(x));
        let cosAng2 = Math.acos(dir2Vector.clone().dot(x));
        // 余弦值计算只能获得夹角，无法判断向量在y轴正负半轴
        if (dir1Vector.y < 0) cosAng1 = 2 * Math.PI - cosAng1
        if (dir2Vector.y < 0) cosAng2 = 2 * Math.PI - cosAng2
        // 圆弧线绘制
        let clockWise = false; //false逆时针  true顺时针
        if (crossDirection > 0) clockWise = true;

        let arcCurve = new THREE.ArcCurve(circleCenter.x, circleCenter.y, this.radius, cosAng1, cosAng2, clockWise);

        pointsArr.push(...arcCurve.getSpacedPoints(10))
      }
    }
    pointsArr.push(new THREE.Vector2(arr[arr.length - 1].x, arr[arr.length - 1].y))
    return pointsArr
  }
  /**
   * @function: 获取线转面的点位数据
   * @param {*} pointsArr 线的点位集合 Vector2[]
   */  
  getPoint(pointsArr) {
    // 对曲线上的顶点坐标进行等间距计算
    var pointsArr1 = [];
    var pointsArr2 = [];
    // 对曲线进行等距计算
    pointsArr.forEach((point, i) => {
      // console.log(i / L)
      // 不使用getTangentAt计算切线
      var z = new THREE.Vector3(0, 0, 1); //沿着z轴方向单位向量
      // 相邻两点相减计算切线
      var tangent = null;
      let currentPoint = null    // 当前点
      let adjacentPoint = null  // 相邻点
      if (pointsArr[i + 1]) {
        currentPoint = pointsArr[i]
        adjacentPoint = pointsArr[i + 1]
        tangent = adjacentPoint.clone().sub(currentPoint).normalize();
      } else {
        adjacentPoint = pointsArr[i - 1]
        currentPoint = pointsArr[i]
        tangent = currentPoint.clone().sub(adjacentPoint).normalize();
      }
      tangent = new THREE.Vector3(tangent.x, tangent.y)
      // 切线绕z轴旋转90度计算垂线
      var vertical = tangent.clone().applyAxisAngle(z, Math.PI / 2);
      var p1 = point.clone().add(vertical.clone().multiplyScalar(this.laneWidth / 2));
      var p2 = point.clone().add(vertical.clone().multiplyScalar(-this.laneWidth / 2));

      pointsArr1.push(p1);
      pointsArr2.push(p2);

    });

    pointsArr2.reverse(); //注意等间距顶点数组倒序
    return pointsArr1.concat(pointsArr2)
  }
  getSharpCornerPoint(pointsArr){
    pointsArr = pointsArr.map(p => new THREE.Vector3(p.x, p.y))
    let pointsArr1 = []
    let pointsArr2 = []
    let [start1, start2] = this.getSpecifiedPoint(pointsArr, 0)
    let [end1, end2] = this.getSpecifiedPoint(pointsArr, pointsArr.length - 1)

    pointsArr1.push(start1)
    pointsArr2.push(start2)
    for (let i = 1; i < pointsArr.length - 1; i++) {
      // 三个点坐标
      let p1 = pointsArr[i - 1];
      let p2 = pointsArr[i];
      let p3 = pointsArr[i + 1];
      // 计算三个点构成的两条线的方向
      let dir1 = p1.clone().sub(p2).normalize();
      let dir2 = p3.clone().sub(p2).normalize();
      // 两条直线角平分线方向
      let angleBisector = dir2.clone().add(dir1).normalize(); // 角平分线
      let angCos = dir1.clone().dot(dir2); //两条直线方向向量夹角余弦值
      let ang = Math.acos(angCos);
      // 对边 / 斜边 = sin  sideLength = 对边(车道宽度的一半) / sin
      let sideLength = (this.laneWidth / 2) / Math.sin(ang / 2); //圆心与两条直接交叉点距离
      let a1 = p2.clone().add(angleBisector.clone().multiplyScalar(-sideLength))
      let a2 = p2.clone().add(angleBisector.clone().multiplyScalar(sideLength))

      if (this.cross(a1, p1, p2) > 0) {
        pointsArr1.push(a1)
        pointsArr2.push(a2)
      } else {
        pointsArr1.push(a2)
        pointsArr2.push(a1)
      }
    }
    pointsArr1.push(end1)
    pointsArr2.push(end2)
    pointsArr2.reverse();
    return pointsArr1.concat(pointsArr2)
  }


}